package com.miet.mp45.filippov.crypto.util;

import java.math.BigInteger;
import java.security.KeyPair;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Calendar;
import java.util.Date;
import java.util.Enumeration;

import javax.security.auth.x500.X500Principal;

import org.bouncycastle.asn1.ASN1Set;
import org.bouncycastle.asn1.DERObjectIdentifier;
import org.bouncycastle.asn1.pkcs.Attribute;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.ExtendedKeyUsage;
import org.bouncycastle.asn1.x509.Extensions;
import org.bouncycastle.asn1.x509.KeyPurposeId;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x509.X509Extension;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v1CertificateBuilder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX500NameUtil;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509v1CertificateBuilder;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.pkcs.PKCS10CertificationRequest;
import org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure;
import org.bouncycastle.x509.extension.SubjectKeyIdentifierStructure;

public class CSRSigner
{
    
    ContentSigner signer;
    X500Name issuer;
    KeyPair rootKeyPair;

    public CSRSigner(X500Name issuer, KeyPair keyPair, String signatureAlgorithm) throws OperatorCreationException
    {
        this.issuer = issuer;
        this.rootKeyPair = keyPair;
        signer = new JcaContentSignerBuilder(signatureAlgorithm).build(keyPair.getPrivate());
    }
    
    private X509CertificateHolder generateV1Certificate()
    {
        // Security.addProvider(new
        // org.bouncycastle.jce.provider.BouncyCastleProvider());

        X500Name subject = issuer;
        BigInteger serial = BigInteger.valueOf(System.currentTimeMillis());
        Date notBefore = new Date(System.currentTimeMillis() - 10000);
        Date notAfter = new Date(System.currentTimeMillis() + 10000);

        X509v1CertificateBuilder certBuilder = 
            new JcaX509v1CertificateBuilder(issuer, serial, notBefore, notAfter, subject, rootKeyPair.getPublic());

        return certBuilder.build(signer);
    }
    
    public X509Certificate[] sign(PKCS10CertificationRequest csr) throws Exception
    {
        X509CertificateHolder rootCert = generateV1Certificate();
        
        X500Name subject = csr.getSubject();
        X500Name issuer = rootCert.getSubject();
        BigInteger serial = BigInteger.valueOf(System.currentTimeMillis());
        Date notBefore = new Date(System.currentTimeMillis());
        Calendar currentDatePlusYear = Calendar.getInstance();
        currentDatePlusYear.setTime(new Date(System.currentTimeMillis()));
        currentDatePlusYear.add(Calendar.YEAR, 1);
        Date notAfter = currentDatePlusYear.getTime();
        SubjectPublicKeyInfo publicKeyInfo = csr.getSubjectPublicKeyInfo();

        X509v3CertificateBuilder certBuilder =
            new X509v3CertificateBuilder(issuer, serial, notBefore, notAfter, subject, publicKeyInfo);


//        Extensions.
//        certBuilder.addExtension(X509Extensions.AuthorityKeyIdentifier, false,
//                new AuthorityKeyIdentifierStructure(rootKeyPair.getPublic()));
//
//        certBuilder.addExtension(X509Extensions.SubjectKeyIdentifier,
//
//        false, new SubjectKeyIdentifierStructure(request.getPublicKey("BC")));
//
//        certBuilder
//                .addExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(false));
//
//        certBuilder.addExtension(X509Extensions.KeyUsage, true, new KeyUsage(
//                KeyUsage.digitalSignature | KeyUsage.keyEncipherment));
//
//        certBuilder.addExtension(X509Extensions.ExtendedKeyUsage, true, new ExtendedKeyUsage(
//                KeyPurposeId.id_kp_serverAuth));

//        Attribute[] attributes = csr.getAttributes();
//        for (Attribute attribute : attributes)
//        {
//            if (attribute.getAttrType().equals(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest))
//            {
//                X509Extensions extensions = X509Extensions.getInstance(attribute.getAttrValues()
//                        .getObjectAt(0));
//
//                Enumeration e = extensions.oids();
//                while (e.hasMoreElements())
//                {
//                    DERObjectIdentifier oid = (DERObjectIdentifier) e.nextElement();
//                    X509Extension ext = extensions.getExtension(oid);
//
//                    certBuilder.addExtension(oid, ext.isCritical(), ext.getValue().getOctets());
//                }
//            }
//        }

        X509CertificateHolder issuedCert = certBuilder.build(signer);

        JcaX509CertificateConverter converter = new JcaX509CertificateConverter();
        return new X509Certificate[] { converter.getCertificate(issuedCert),
                                       converter.getCertificate(rootCert) };
    }
}
